
#include <iostream>
#include <string>
#include <vector>
#include <type_traits>

using namespace std;

template<typename T>
struct has_member_value_type
{
    template<typename S>
    static void check(int, typename S::value_type * s = nullptr);
    template<typename S>
    static int check(...);

    enum { value = std::is_void<decltype(check<T>(0))>::value };
};

template<typename T>
void print__(T const & t)
{
    cout << t << endl;
}
template<char _Sep = 0, typename T0>
void print(T0 const & t0);

template<typename T>
void print_(T const & v, false_type * b = 0)
{
    cout << v;
}

template<typename T>
void print_(T const & s, true_type * b = 0)
{
    print("{");
    for(auto & i : s)
    {
        print(i);
    }
    print("}");
}

template<char _Sep, typename T0>
void print(T0 const & t0)
{
    print_<_Sep>(t0, (bool_constant<has_member_value_type<T0>::value>*)0);
    cout << endl;
}

template<char _Sep = 0, typename T0, typename ...T>
void print(T0 const & t0, T ...t)
{
	if(_Sep) print(t0, _Sep);
	else print(t0);
	print<_Sep>(t...);
}

auto a = "hello";

int main() {

    print<' '>(std::vector<int>{1, 2, 3, 4}, 2, 3, 4, 5);
	print<','>(strlen(a), 0, 2, 3, "what", "what"s, u"123");
	print(sizeof("12345"));
	print(strlen(a), 0, 2, 3, "what"s);
}
